/**
 * @class   wosh::gui::WidgetVariant
 * @brief   
 *          
 *          
 *
 ****************************************************************************
 * @version $Id: WidgetVariant.h 2184 2010-03-20 13:19:23Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Gui_WidgetVariantEditor_H__
 #define __WOSH_Gui_WidgetVariantEditor_H__

 #include <core/Variant.h>
 #include <framework/gui/IWidgetSerializable.h>
 #include <framework/gui/GuiUtilities.h>


 #include <QDateTime>
 #include <QtGui/QMenu>
 #include <QtGui/QContextMenuEvent>

 #include <QtGui/QLineEdit>
 #include <QtGui/QComboBox>
 #include <QtGui/QLabel>
 #include <QtGui/QSlider>
 #include <QtGui/QCheckBox>
 #include <QtGui/QSpinBox>


namespace Ui {
    class WidgetUriSelector;
}
namespace wosh {
 namespace gui {


class WidgetVariant :  public virtual IWidgetSerializable  {

	public:
		WidgetVariant() { }
		virtual ~WidgetVariant() { }

	public:
		virtual void setData( const Variant& new_data )	{ this->myData = new_data; this->timestamp = QDateTime::currentDateTime(); }

		virtual const Variant& getData() const				{ return this->myData; }
		virtual Variant& getData()							{ return this->myData; }

	public:
		virtual WRESULT loadObject( const ISerializable* object ) {
			this->myData.clear();
			if ( object == NULL ) return WRET_OK;
			if ( !object->isClass(_Variant_TYPE) ) return WRET_ERR_PARAM;
			const wosh::Variant* newData = dynamic_cast<const wosh::Variant*>(object);
			if ( newData == NULL ) return WRET_ERR_PARAM;
			setData(*newData);
			return WRET_OK;
		 }

		virtual WRESULT saveObject( ISerializable* object ) const {
			if ( object == NULL ) return WRET_ERR_PARAM;
			if ( !object->isClass(_Variant_TYPE) ) return WRET_ERR_PARAM;
			wosh::Variant* newData = dynamic_cast<wosh::Variant*>(object);
			if ( newData == NULL ) return WRET_ERR_PARAM;
			*newData = getData();
			return WRET_OK;
		 }

		virtual inline ISerializable* newObject() const	{ return new Variant(); }

		virtual const char* getSerializableType() const	{ return _Variant_TYPE; }

		inline QString getDataType() const				{ return QString(this->myData.getTypeAsString()); }

	protected:
		wosh::Variant myData;
		QDateTime timestamp;

}; // class def

// ----------------------------------------------------------------------------------------


class WidgetVariantLabel :  public QLabel, public virtual WidgetVariant  {

	Q_OBJECT

	public:
		WidgetVariantLabel(QWidget* parent = NULL) : WidgetVariant(), QLabel(parent) { }
		virtual ~WidgetVariantLabel() { }

		virtual QWidget* asQWidget() { return this; }

	public:
		virtual void setData( const Variant& new_data ) {
			WidgetVariant::setData(new_data);
			QVariant qvar = GuiUtilities::convertVariant2QVariant( &new_data, Variant::STRING );
			this->setText( qvar.toString() );
			this->setToolTip(tr("%1 [updated at %2]").arg(getDataType()).arg(this->timestamp.toString()));
		 }

}; // class def

// ----------------------------------------------------------------------------------------


class WidgetVariantEditor :  public QLineEdit, public WidgetVariant  {

	Q_OBJECT

	public:
		WidgetVariantEditor(QWidget* parent = NULL) : QLineEdit(parent), WidgetVariant() {
			connect(this, SIGNAL(editingFinished()), this, SLOT(check_update()));
		 }

		virtual ~WidgetVariantEditor() { }

		virtual QWidget* asQWidget() { return this; }

	public:
		virtual void setData( const Variant& new_data ) {
			WidgetVariant::setData(new_data);
			QVariant qvar = GuiUtilities::convertVariant2QVariant( &new_data, Variant::STRING );
			this->setText( qvar.toString() );
			this->setToolTip(tr("%1 [updated at %2]").arg(getDataType()).arg(this->timestamp.toString()));
		 }

	protected:
		virtual void contextMenuEvent( QContextMenuEvent* menu_event ) {
			QMenu* menu = createStandardContextMenu();
			QMenu* menuType = new QMenu(this);
			menuType->setTitle("Type");
			menuType->addAction("String (STR)");
			menuType->addAction("Integer (INT)");

			QAction* sep = menu->insertSeparator( menu->actions().first());
			menu->insertMenu(sep, menuType);

			menu->exec(menu_event->globalPos());
			delete menu;
		 }

	protected slots:
		void check_update() {
			if ( !myData.isString() || myData.asString() != text().toLatin1().data() ) {
				myData.set( text().toLatin1().data() );
				emit updatedObject();
			 }
		 }

	signals:
		void updatedObject();

}; // class def

// ----------------------------------------------------------------------------------------


class WidgetVariantComboBox :  public QComboBox, public WidgetVariant  {

	Q_OBJECT

	public:
		WidgetVariantComboBox(QWidget* parent = NULL) : QComboBox(parent), WidgetVariant() {
			connect(this, SIGNAL(activated(int)), this, SLOT(check_update(int)));
		 }

		virtual ~WidgetVariantComboBox() { }

		virtual QWidget* asQWidget() { return this; }

	public:
		virtual void setData( const Variant& new_data ) {
			WidgetVariant::setData(new_data);
			if ( new_data.isNumeric() )
				this->setCurrentIndex( new_data.toInteger(0) );
			else {
				for(int i=0;i<count(); i++) {
					if ( itemText(i) != QString(new_data.toString().c_str()) ) continue;
					this->setCurrentIndex( i );
					break;
				 }
			 }
		 }

	protected slots:
		void check_update( int i ) {
			if ( myData.toLong(0) != i ) {
				myData.set( (long)i );
				emit updatedObject();
			 }
		 }

	signals:
		void updatedObject();

}; // class def

// ----------------------------------------------------------------------------------------


class WidgetVariantSlider :  public QSlider, public WidgetVariant  {

	Q_OBJECT

	public:
		WidgetVariantSlider(QWidget* parent = NULL) : QSlider(parent), WidgetVariant() {

		 }

		virtual ~WidgetVariantSlider() { }

		virtual QWidget* asQWidget() { return this; }

	public:
		virtual void setData( const Variant& new_data ) {
			WidgetVariant::setData(new_data);
			if ( new_data.isInteger() )
				this->setValue( new_data.toInteger(0) );
			else if ( new_data.isLong() )
				this->setValue( new_data.toLong(0) );
			else if ( new_data.isInt64() )
				this->setValue( new_data.toInt64(0) );
		 }

	signals:
		void updatedObject();

}; // class def

// ----------------------------------------------------------------------------------------


class WidgetVariantSpinBox :  public QSpinBox, public WidgetVariant  {

	Q_OBJECT

	public:
		WidgetVariantSpinBox(QWidget* parent = NULL) : QSpinBox(parent), WidgetVariant() {
			connect(this, SIGNAL(editingFinished()), this, SLOT(check_update()));
		 }

		virtual ~WidgetVariantSpinBox() { }

		virtual QWidget* asQWidget() { return this; }

	public:
		virtual void setData( const Variant& new_data ) {
			WidgetVariant::setData(new_data);
			if ( new_data.isInteger() )
				this->setValue( new_data.toInteger(0) );
			else if ( new_data.isLong() )
				this->setValue( new_data.toLong(0) );
			else if ( new_data.isInt64() )
				this->setValue( new_data.toInt64(0) );
		 }

	protected slots:
		void check_update() {
			if ( myData.toLong(0) != value() ) {
				myData.set( (long)value() );
				emit updatedObject();
			 }
		 }

	signals:
		void updatedObject();

}; // class def

// ----------------------------------------------------------------------------------------


class WidgetVariantCheckBox :  public QCheckBox, public WidgetVariant  {

	Q_OBJECT

	public:
		WidgetVariantCheckBox(QWidget* parent = NULL) : QCheckBox(parent), WidgetVariant() {
			connect(this, SIGNAL(clicked()), this, SLOT(check_update()));
		 }

		virtual ~WidgetVariantCheckBox() { }

		virtual QWidget* asQWidget() { return this; }

	public:
		virtual void setData( const Variant& new_data ) {
			this->myData = new_data;
			this->setChecked( new_data.toBoolean(false) );
		 }

	protected slots:
		void check_update() {
			if ( !myData.isBoolean() || myData.toBoolean(false) != isChecked() ) {
				myData.set( (bool)isChecked() );
				emit updatedObject();
			 }
		 }

	signals:
		void updatedObject();

}; // class def








 }; // namespace gui
}; // namespace wosh


#endif //__WOSH_Gui_WidgetVariantEditor_H__
